/*
 * Copyright (C) 2005 Samuel Abels <spam debain org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 */

using System;
using System.Collections;
using System.Threading;

public class EventQueue
{
  private ArrayList eventQueue;
  private object    eventQueueLock;

  public EventQueue ()
  {
    eventQueue     = new ArrayList();
    eventQueueLock = new Object();
  }

  /**
   * Given a function (or an event) this method returns a functor.
   */
  public static Functor<TRet> BindOne<TRet, TArg> (Functor<TRet, TArg> gen, TArg arg)
  {
    return new Functor<TRet> (
      new _FunctorInfo<TRet, TArg>(gen, arg).Invoke
    );
  }

  /**
   * Push one event on the event queue, to be emitted by the next Glib.Idle
   * loop.
   * \param func The function to be called.
   */
  public void Queue (Functor<void> func_)
  {
    lock (eventQueueLock) {
      eventQueue.Add (func_);
    }
    GLib.Idle.Add(new GLib.IdleHandler(callEvents));
  }

  /**
   * Calls all events that are currently in the event queue.
   */
  private bool callEvents ()
  {
    // Copy the event list.
    ArrayList events = new ArrayList();
    lock (eventQueueLock) {
      foreach (Functor<void> function in eventQueue)
        events.Add(function);
      eventQueue.Clear();
    }

    // Invoke every event.
    foreach (Functor<void> function in events)
      function();
    return false;
  }

  /**
   * This is only necessary to work around a Mono bug;
   * might be replaced by an anonymous delegate later.
   */
  private class _FunctorInfo<TRet, TArg> {
    private Functor<TRet, TArg> gen;
    private TArg                arg;

    internal _FunctorInfo (Functor<TRet, TArg> gen, TArg arg)
    {
      this.gen = gen;
      this.arg = arg;
    }

    public TRet Invoke ()
    {
      return gen (arg);
    }
  }
} // class EventQueue
